package com.stone.boot.pipeline.api.controller.v1;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.stone.boot.pipeline.app.service.PipelineRedisService;
import com.stone.boot.pipeline.app.service.PipelineService;
import com.stone.boot.pipeline.config.StonePipelineSwaggerTagConfig;
import com.stone.boot.pipeline.domain.entity.Pipeline;
import com.stone.boot.pipeline.domain.repository.PipelineRepository;
import com.stone.boot.pipeline.domain.vo.PipelineVO;
import com.stone.starter.core.base.BaseController;
import com.stone.starter.core.util.result.Results;
import io.choerodon.mybatis.pagehelper.PageHelper;
import io.choerodon.mybatis.pagehelper.annotation.SortDefault;
import io.choerodon.mybatis.pagehelper.domain.PageRequest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.hzero.mybatis.helper.SecurityTokenHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.List;

/**
 * 流程器控制器
 *
 * @author Mr_wenpan@163.com 2021/08/05 21:43
 */
@RestController("pipelineController.vPipelineController1")
@RequestMapping("/v1/pipeline")
@Api(tags = StonePipelineSwaggerTagConfig.PIPELINE)
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class PipelineController extends BaseController {

    private final PipelineService pipelineService;

    private final PipelineRepository pipelineRepository;

    private final PipelineRedisService pipelineRedisService;

    private static final String APPLICATION_OCTET_STREAM_CHARSET_UTF_8 = "application/octet-stream; charset=utf-8";

    @GetMapping
    @ApiOperation(value = "流程器列表")
    public ResponseEntity<?> list(Pipeline pipeline,
                                  @ApiIgnore @SortDefault(value = Pipeline.FIELD_ID) PageRequest pageRequest) {
        return Results.success(PageHelper.doPage(pageRequest.getPage(),
                pageRequest.getSize(), () -> pipelineRepository.listPipeline(pipeline)));
    }

    @GetMapping("/{id}")
    @ApiOperation(value = "流程器明细")
    public ResponseEntity<?> detail(@PathVariable Long id) {
        return Results.success(pipelineRepository.selectByPrimaryKey(id));
    }

    @Deprecated
    @PostMapping
    @ApiOperation(value = "批量新增或修改流程器")
    public ResponseEntity<?> create(@RequestBody List<Pipeline> pipelines) {
        int errorCount = pipelineService.batchMerge(pipelines);
        if (0 == errorCount) {
            return Results.success(Collections.emptyList());
        } else {
            String resultString = "流水线编码不可重复" + "，成功保存" + (pipelines.size() - errorCount) + "条数据";
            return Results.success(Collections.singletonList(resultString));
        }
    }

    @PostMapping("/batch-create-and-update")
    @ApiOperation(value = "批量新增和修改流程器综合方法（重写）")
    public ResponseEntity<?> batchCreateAndUpdate(@RequestBody List<Pipeline> pipelines) {
        pipelineService.batchCreateAndUpdate(pipelines);
        return Results.success();
    }

    @PutMapping("/batch-update")
    @ApiOperation(value = "批量修改流程器")
    public ResponseEntity<?> batchUpdate(@RequestBody List<Pipeline> pipelines) {
        pipelineService.batchUpdate(pipelines);
        return Results.success();
    }

    @PostMapping("/batch-insert")
    @ApiOperation(value = "批量新增流程器")
    public ResponseEntity<?> batchInsert(@RequestBody List<Pipeline> pipelines) {
        pipelineService.batchInsert(pipelines);
        return Results.success();
    }

    @DeleteMapping
    @ApiOperation(value = "批量删除流程器")
    public ResponseEntity<?> remove(@RequestBody List<Pipeline> pipelines) {
        SecurityTokenHelper.validToken(pipelines);
        pipelineRepository.batchDeleteByPrimaryKey(pipelines);
        return Results.success();
    }

    @DeleteMapping
    @ApiOperation(value = "批量删除流程器(重写)")
    public ResponseEntity<?> batchRemove(@RequestBody List<Pipeline> pipelines) {
        SecurityTokenHelper.validToken(pipelines);
        pipelineService.batchRemove(pipelines);
        pipelineRepository.batchDeleteByPrimaryKey(pipelines);
        return Results.success();
    }

    @GetMapping("/cache/{code}")
    @ApiOperation(value = "流程器Redis缓存信息")
    public ResponseEntity<?> getRedisConfigInfo(@PathVariable String code) {
        return Results.success(pipelineRedisService.getPipelineConf(code));
    }

    @ApiOperation(value = "流程器yaml导入")
    @PostMapping(value = "/yaml/upload", headers = "content-type=multipart/form-data")
    public ResponseEntity<?> uploadPipelineYaml(@ApiParam(value = "上传的文件", required = true)
                                                @RequestParam(value = "yamlFiles") List<MultipartFile> multipartFiles) {
        if (CollectionUtils.isEmpty(multipartFiles)) {
            return new ResponseEntity<>("文件为空", HttpStatus.OK);
        }
        boolean blankFilename = multipartFiles.stream().map(MultipartFile::getOriginalFilename).anyMatch(StringUtils::isBlank);
        if (blankFilename) {
            return new ResponseEntity<>("文件名不能为空", HttpStatus.OK);
        }
        pipelineService.savePipelineDTOS(multipartFiles);
        return Results.success("导入成功");
    }

    @GetMapping("/yaml/download/{id}")
    @ApiOperation(value = "流程器yaml导出")
    public ResponseEntity<?> downloadPipelineYaml(@PathVariable Long id, HttpServletResponse response) {
        // 使用ObjectMapper来写出yml文件
        ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
        PipelineVO pipelineDTO = pipelineService.getPipelineDTO(id);
        try {
            // 必要地清除response中的缓存信息
            response.reset();
            response.setContentType(APPLICATION_OCTET_STREAM_CHARSET_UTF_8);
            mapper.writeValue(response.getOutputStream(), pipelineDTO);
        } catch (IOException e) {
            return Results.error(e);
        }
        return Results.success();
    }
}
